﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ttlang.compiler
{
    public static class compiler_doc
    {
        public static bool ParseNode_Doc_1Pass(CompilerContext context, src.AstNode innode)
        {
            Debug.Assert(innode.type == "doc");
            foreach (var n in innode.children)
            {
                ParseNode_1Pass(context, n);
            }
            return true;
        }
        static bool ParseNode_1Pass(CompilerContext context, src.AstNode innode)
        {
            switch (innode.type)
            {
                case "docitem":
                    return ParseNode_1Pass(context, innode.children[0]);//直接脱壳
                case "namespace_def":
                    {
                        string name = "";
                        int childstart = 0;
                        //0 namespce
                        //1 id
                        //2 {
                        //end }
                        for (var i = 0; i < innode.children.Count; i++)
                        {
                            if (innode.children[i].text == "namespace")
                            {
                                name = innode.children[i + 1].text;
                                childstart = i + 3;
                                break;
                            }
                        }

                        semantic.IContainer parentContainer = context.GetParentContainer();
                        semantic.TTNameSpace _namespace = null;
                        if (parentContainer.namespaces == null || parentContainer.namespaces?.TryGetValue(name, out _namespace) == false)
                        {
                            _namespace = new semantic.TTNameSpace(context.module,
                             context.stack_namespace.Count == 0 ? null : context.stack_namespace.Peek(),
                             name);
                            parentContainer.AddNameSpace(_namespace);
                        }

                        Debug.Assert(_namespace != null);


                        context.stack_namespace.Push(_namespace);
                        {

                            //收集一次注释
                            foreach (var c in context.stack_comment)
                            {
                                _namespace.AddComment(c);
                            }
                            context.stack_comment.Clear();



                            for (var i = childstart; i < innode.children.Count - 1; i++)
                            {
                                if (innode.children[i].text == ";") //空行
                                    continue;
                                if (!ParseNode_1Pass(context, innode.children[i]))
                                    return false;
                            }

                            //完了再收集一次注释
                            foreach (var c in context.stack_comment)
                            {
                                _namespace.AddComment(c);
                            }
                            context.stack_comment.Clear();

                        }
                        context.stack_namespace.Pop();
                    }
                    return true;

                case "comment":
                case "COMMENTSINGLE":
                case "COMMENTMUL":
                    context.stack_comment.Push(innode.text);
                    return true;

                case "class_def":
                case "struct_def":
                    {
                        semantic.IContainer parentContainer = context.GetParentContainer();
                        if (parentContainer.type == semantic.ContainerType.Type)
                            throw new Exception("must be namespace");
                        string name = "";
                        int childstart = 0;
                        //还可以有各种modifer
                        //0 class
                        //1 id
                        //2 {
                        //end }
                        semantic.DEFINETYPE deftype = semantic.DEFINETYPE.ERROR;
                        for (var i = 0; i < innode.children.Count; i++)
                        {
                            if (innode.children[i].text == "class")
                            {
                                deftype = semantic.DEFINETYPE.CLASS;
                                name = innode.children[i + 1].text;
                                childstart = i + 3;
                                break;
                            }
                            if (innode.children[i].text == "struct")
                            {
                                deftype = semantic.DEFINETYPE.STRUCT;
                                name = innode.children[i + 1].text;
                                childstart = i + 3;
                                break;
                            }
                        }
                        var _type = new semantic.TTType(context.module, parentContainer, name, deftype, false);
                        parentContainer.AddType(_type);

                        context.stack_class.Push(_type);
                        {

                            //收集一次注释
                            foreach (var c in context.stack_comment)
                            {
                                _type.AddComment(c);
                            }
                            context.stack_comment.Clear();


                            for (var i = childstart; i < innode.children.Count - 1; i++)
                            {
                                if (!ParseNode_1Pass(context, innode.children[i]))
                                    return false;
                            }




                            //收集一次注释
                            foreach (var c in context.stack_comment)
                            {
                                _type.AddComment(c);
                            }
                            context.stack_comment.Clear();
                        }
                        context.stack_class.Pop();
                    }
                    return true;
                case "function_def"://全局函数 function 就是global_method
                    {
                        semantic.IContainer parentContainer = context.GetParentContainer();
                        if (parentContainer.type == semantic.ContainerType.Type)
                            throw new Exception("must be namespace");


                        var _method = semantic.TTMethod.Create(context, parentContainer, innode);
                        parentContainer.AddMethod(_method);
                        return true;
                    }
                case "global_value_def"://全局变量
                    {
                        semantic.IContainer parentContainer = context.GetParentContainer();
                        if (parentContainer.type == semantic.ContainerType.Type)
                            throw new Exception("must be namespace");


                        //0 var
                        //1 id
                        string name = innode.children[1].text;
                        var _var = semantic.TTVar.Create(context, parentContainer, innode);
                        parentContainer.AddVar(_var);
                        return true;
                    }
                case "enum_def":
                    {
                        semantic.IContainer parentContainer = context.GetParentContainer();
                        if (parentContainer.type == semantic.ContainerType.Type)
                            throw new Exception("must be namespace");
                    }
                    throw new NotImplementedException();

                case "method_def":
                case "method_def_withbody":
                case "method_def_nobody":
                    {
                        semantic.IContainer parentContainer = context.GetParentContainer();
                        if (parentContainer is semantic.TTType _class)
                        {
                            //需要多次处理相似逻辑，封装
                            semantic.TTMethod _method = semantic.TTMethod.Create(context, _class, innode);
                            _class.AddMethod(_method);


                            return true;

                        }



                        throw new Exception("must be class");
                    }
                case "value_def":
                    {
                        semantic.IContainer parentContainer = context.GetParentContainer();
                        if (parentContainer.type == semantic.ContainerType.NameSpace)
                            throw new Exception("must be class");

                        var _var = semantic.TTVar.Create(context, parentContainer, innode);
                        parentContainer.AddVar(_var);
                        return true;
                    }
                default:
                    throw new NotImplementedException();
            }
        }
    }
}
